#include "widget.h"
#include "ui_widget.h"
#include <QPainter>
#include <QRandomGenerator>
#include <QApplication>
#include <QFileDialog>
#include <QmessageBox>

//Widget类的构造函数
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
    //初始化游戏结束标志
    , gameOver(false)
{
    ui->setupUi(this);

    //定义窗口大小
        this->setFixedSize(800,600);

    //创建定时器
        timer = new QTimer();
        //信号槽  定时器超时执行timeout()槽函数
        connect(timer,SIGNAL(timeout()),this,SLOT(timeout()));

    //初始化蛇身
        QRectF rect(400,300,nodeWidth,nodeHeight);
        //小方块加到蛇身上
        snake.append(rect);
        //初始化长度是3
        addTop();
        addTop();

    //初始化奖品，随机位置生成
        addNewReword();

}

//析构函数 释放内存
Widget::~Widget()
{
    delete ui;
}

//按键控制蛇的方向
void Widget::keyPressEvent(QKeyEvent *event)
{
    //根据用户按下的上下左右箭头更新蛇的方向 蛇不能反向移动 例如向上移动不能按下箭头
    switch (event->key())
    {
    case Qt::Key_Up:
        if(moveFlag != DIR_DOWN){moveFlag = DIR_UP;}
        break;
    case Qt::Key_Down:
        if(moveFlag != DIR_UP){moveFlag = DIR_DOWN;}
        break;
    case Qt::Key_Right:
        if(moveFlag != DIR_LEFT){moveFlag = DIR_RIGHT;}
        break;
    case Qt::Key_Left:
        if(moveFlag != DIR_RIGHT){moveFlag = DIR_LEFT;}
        break;
    //空格键开始、暂停游戏
    case Qt::Key_Space:
        if(gameStart == false)
        {
            gameStart = true;
            //启动定时器，开始游戏
            timer->start(time);
        }
        else
        {
            gameStart = false;
            //停止定时器，暂停游戏
            timer->stop();
        }
        break;
    default:
        break;
    }
}

//超时函数
void Widget::timeout()
{
    //判断蛇头矩形有没有和奖品矩形相交
    int count = 1;
    if(snake[0].intersects(rewardNode))
    {
        //相交就吃掉
        count++;
        //得分加一
        score++;
        //生成一个新的
        addNewReword();
    }
    while (count--)
    {
        //根据当前按键方向移动蛇
        switch (moveFlag)
        {
        case DIR_UP:
            addTop();
            break;
        case DIR_DOWN:
            addDown();
            break;
        case DIR_LEFT:
            addLeft();
            break;
        case DIR_RIGHT:
            addRight();
            break;
        default:
            break;
        }
    }
    if(checkContact())
    {
        timer->stop();
        gameStart= false;
        gameOver= true;
        //更新界面显示游戏结束
        update();

        //弹出对话框
        QMessageBox::StandardButton reply;
        reply= QMessageBox::question(this,"游戏结束","再来一局？",
                                    QMessageBox::Yes | QMessageBox::No);

        //再来一局，重置游戏
        if(reply == QMessageBox::Yes)
        {
            resetGame();
        }
        //退出
        else
        {
            QApplication::quit();
        }
    }
    //蛇头前进一格，删除一格蛇尾，模拟蛇的运动
    deleteLast();
    //更新
    update();

}

//接下来四个函数让我们的贪吃蛇根据当前移动方向移动
//上面
void Widget::addTop()
{
   //两个变量存储蛇头小方块左上角和右下角坐标
    QPointF leftTop;
    QPointF rightBotom;

    //检查是否超出上边界
    //超出，则蛇从下边界重新出现
    if(snake[0].y()-nodeHeight < 0)//蛇头矩形左上角y坐标
    {
        //this->height返回窗口高度
        leftTop = QPoint(snake[0].x(),this->height()-nodeHeight);
    }
    else
    {
        //未超出，蛇头向上移动一格
        leftTop = QPointF(snake[0].x(),snake[0].y()-nodeHeight);
    }
    //通过左上角坐标计算得到右下角坐标
    rightBotom = leftTop+QPointF(nodeWidth,nodeHeight);
    //创建新的小方块并加入
    snake.insert(0,QRectF(leftTop,rightBotom));
}

//下面
void Widget::addDown()
{
    //两个变量存储蛇头小方块左上角和右下角坐标
    QPointF leftTop;
    QPointF rightBotom;

    //检查是否超出下边界
    //超出，则蛇从上边界重新出现
    if(snake[0].y()+nodeHeight*2 > this->height())
    {
        //蛇头左上角y坐标设置为0
        leftTop = QPointF(snake[0].x(),0);
    }
    else
    {
        //未超出，蛇头向下移动一格，蛇头左下角坐标赋值给新的左上角坐标
        leftTop = snake[0].bottomLeft();
    }
    //通过左上角坐标计算得到右下角坐标
    rightBotom = leftTop+QPointF(nodeWidth,nodeHeight);
    //创建新的小方块并加入
    snake.insert(0,QRectF(leftTop,rightBotom));
}

//左侧
void Widget::addLeft()
{
    //两个变量存储蛇头小方块左上角和右下角坐标
    QPointF leftTop;
    QPointF rightBotom;

    //检查是否超出左边界
    //超出，则蛇从右边界重新出现
    if(snake[0].x()-nodeWidth < 0)
    {
        leftTop = QPointF(this->width()-nodeWidth,snake[0].y());
    }
    //未超出，蛇头向左移动，蛇头小方块左上角x坐标减去nodeWidth表示蛇头左移一格
    else
    {
        leftTop = snake[0].topLeft()-QPointF(nodeWidth,0);
    }
    //通过左上角坐标计算得到右下角坐标
    rightBotom = leftTop+QPointF(nodeWidth,nodeHeight);
    //创建新的小方块并加入
    snake.insert(0,QRectF(leftTop,rightBotom));
}


//右侧
void Widget::addRight()
{
    //两个变量存储蛇头小方块左上角和右下角坐标
    QPointF leftTop;
    QPointF rightBotom;

    //检查是否超出右边界
    //超出，则蛇从左边界重新出现
    if(snake[0].x()-nodeWidth*2 > this->width())
    {
        leftTop = QPointF(0,snake[0].y());
    }
    else
    {
        //未超出，蛇头向右移动，右上角坐标赋值给新的左上角坐标
        leftTop = snake[0].topRight();
    }
    //通过左上角坐标计算得到右下角坐标
    rightBotom = leftTop+QPointF(nodeWidth,nodeHeight);
    //创建新的小方块并加入
    snake.insert(0,QRectF(leftTop,rightBotom));
}


//绘图
void Widget::paintEvent(QPaintEvent *event)
{
    //创建画家
    QPainter painter(this);
    //画笔
    QPen pen;
    //画刷
    QBrush brush;
    //背景图片
    QPixmap pix;
    pix.load("D:/Qt/t01f97e01794c9ad66a.png");
    painter.drawPixmap(0,0,800,600,pix);

    //绘制贪吃蛇
    pen.setColor(Qt::black);
    brush.setColor(Qt::blue);
    brush.setStyle(Qt::SolidPattern);
    painter.setPen(pen);
    painter.setBrush(brush);

    //通过遍历数组绘制贪吃蛇
    for(int i=0;i<snake.length();i++)
    {
        painter.drawRect(snake[i]);
    }

    //绘制奖品
        pen.setColor(Qt::red);
        brush.setColor(Qt::red);
        brush.setStyle(Qt::SolidPattern);
        painter.setPen(pen);
        painter.setBrush(brush);
        //椭圆(外接矩形是rewardNode)
        painter.drawEllipse(rewardNode);

    //判断蛇头是否碰到蛇身
        if(checkContact())
        {
            QFont font("方块输出",30);
            painter.setFont(font);
            painter.setPen(Qt::black);
            painter.drawText
                (
                    (this->width()-300)/2,
                    (this->height()-30)/2,
                    QString("游戏结束")
                );
            //停止定时器
            timer->stop();
        }

    //绘制得分
    QFont scoreFont("方块输出", 20);
    painter.setFont(scoreFont);
    painter.setPen(Qt::black);
    painter.drawText(10, this->height() - 30, QString("得分: %1").arg(score));

    //调用一下父类的绘图
    QWidget::paintEvent(event);
}

//移除蛇尾
void Widget::deleteLast()
{
    snake.removeLast();
}

//随机位置生成奖品
void Widget::addNewReword()
{
    int width = this->width();
    int a = QRandomGenerator::global()->bounded(width/20*20);
    int height = this->height();
    int b = QRandomGenerator::global()->bounded(height/20*20);
    //定义一个矩形表示奖品的位置和大小
    rewardNode = QRectF
        (
            a,
            b,
            nodeWidth,
            nodeHeight
        );
}

//判断蛇头是否碰到蛇身的函数
bool Widget::checkContact()
{
    for(int i = 1; i < snake.length(); i++)
        for (int j = i+1; j < snake.length(); j++)
        {
            //检查是否有任何一个蛇身方块与其他方块重叠
            if (snake[i] == snake[j])
            {
                return true;
            }
        }
    return false;
}

//重置游戏
void Widget::resetGame()
{
    //重置蛇状态
    snake.clear();
    QRectF rect(400, 300, nodeWidth, nodeHeight);
    snake.append(rect);
    addTop();
    addTop();
    addTop();

    //重置方向和奖品
    moveFlag = DIR_UP;
    addNewReword();

    //重置游戏状态
    gameOver = false;
    gameStart = true;

    //重启游戏
    timer->start(time);
    update();
}






